//
// Created by root on 17-3-11.
//

#include <cstring>
#include <thread>
#include <fstream>
#include "json.h"
#include "yaml.h"
#include "sand.h"
#include "ctrl_cfg.h"
#include "ctrl_spdlog.h"

CtrlCfg::CtrlCfg() {

}

CtrlCfg::~CtrlCfg() {

}

void CtrlCfg::set_config_file(std::string &cfg_file) {
    _config_file = cfg_file;
}

std::string CtrlCfg::get_config_file() {
    return _config_file;
}

void CtrlCfg::set_config_st(Yaml_Config_ST conf) {
    memset(&_config_st, 0, sizeof(_config_st));
    _config_st.on_timer_delete_file = conf.on_timer_delete_file;
    _config_st.file_cache_interval = conf.file_cache_interval;
    _config_st.sdklog_level = conf.sdklog_level;
    stpcpy(_config_st.sdklog_dir, conf.sdklog_dir);
    _config_st.sdklog_autodel = conf.sdklog_autodel;
    stpcpy(_config_st.snapshot_picture_path, conf.snapshot_picture_path);
    _config_st.snapshot_picture_quality = conf.snapshot_picture_quality;
    _config_st.snapshot_picture_size = conf.snapshot_picture_size;
    stpcpy(_config_st.upload_mode, conf.upload_mode);
    stpcpy(_config_st.upload_path, conf.upload_path);
    stpcpy(_config_st.mqtt_host, conf.mqtt_host);
    _config_st.mqtt_port = conf.mqtt_port;
    _config_st.mqtt_keepalive = conf.mqtt_keepalive;

    std::copy(conf.dev_map.begin(), conf.dev_map.end(),
              std::inserter(_config_st.dev_map, _config_st.dev_map.end()));
}

CtrlCfg::Yaml_Config_ST CtrlCfg::get_config_st() {
    return _config_st;
}

CtrlCfg::Dev_Config_Map CtrlCfg::get_dev_config_map() {
    return _dvr_cfg_map;
}

std::string CtrlCfg::get_yaml_config_info() {
    CtrlCfg::Dev_Config_Map config_map = get_dev_config_map();
    Yaml_Config_ST config_st = get_config_st();

    Json::Value pong_json;
    Json::Value cfg_json;
    Json::Value data_json;

    cfg_json["api"] = "v1.0";
    cfg_json["cmd"] = "cfginfo";
    cfg_json["type"] = "mqtt_res"; // mqtt_req / mqtt_res
    cfg_json["date"] = sand::as_seconds(sand::now()) - 3600*8;

    Json::Value general_json;
    general_json["sdklog_dir"] = config_st.sdklog_dir;
    general_json["sdklog_level"] = config_st.sdklog_level;
    general_json["sdklog_autodel"] = config_st.sdklog_autodel;
    general_json["applog_level"] = config_st.applog_level;
    general_json["on_timer_delete_file"] = config_st.on_timer_delete_file;
    general_json["file_cache_interval"] = config_st.file_cache_interval;
    //cfg_json["basic"] = basic_json;
    data_json["general"] = general_json;

    Json::Value devinfo_json;
    for (auto it=config_map.begin(); it != config_map.end(); ++it) {
        devinfo_json["serial"] = it->second.dev_serial;
        devinfo_json["ip"] = it->second.dev_ip;
        devinfo_json["port"] = it->second.dev_port;
        devinfo_json["username"] = it->second.dev_username;
        devinfo_json["password"] = it->second.dev_password;
        //cfg_json["devinfo"] = devinfo_json;
        data_json["devinfo"] = devinfo_json;
    }

    Json::Value snapshot_json;
    snapshot_json["picture_path"] = config_st.snapshot_picture_path;
    snapshot_json["picture_quality"] = config_st.snapshot_picture_quality;
    snapshot_json["picture_size"] = config_st.snapshot_picture_size;
    snapshot_json["upload_mode"] = config_st.upload_mode;
    snapshot_json["upload_path"] = config_st.upload_path;
    //cfg_json["snapshot"] = snapshot_json;
    data_json["snapshot"] = snapshot_json;

    Json::Value mqtt_json;
    mqtt_json["host"] = config_st.mqtt_host;
    mqtt_json["port"] = config_st.mqtt_port;
    mqtt_json["keepalive"] = config_st.mqtt_keepalive;
    //cfg_json["mqtt"] = mqtt_json;
    data_json["mqtt"] = mqtt_json;

    cfg_json["value"] = data_json;

    pong_json.append(cfg_json);

    Json::FastWriter fastWriter;
    std::string config_info = fastWriter.write(pong_json);

    return config_info;
}

bool CtrlCfg::update_general_config(std::string sdklog_dir,
                                    uint32_t sdklog_level,
                                    bool sdklog_autodel,
                                    uint32_t applog_level,
                                    bool on_timer_delete_file,
                                    uint32_t file_cache_interval) {

    std::string config_file = get_config_file();
    if (config_file.empty())
        return false;

    YAML::Node root = YAML::LoadFile(config_file);
    YAML::Node config_root;

    if (root && !root.IsNull()) {
        for (auto it=root.begin(); it!=root.end(); ++it) {
            if (it->first && it->first.as<std::string>().compare("general") == 0) {
                if (it->second && !it->second.IsNull()) {
                    if (_general_map["sdklog_dir"]) {
                        it->second["sdklog"]["logdir"] = sdklog_dir;
                        strcpy(_config_st.sdklog_dir, sdklog_dir.c_str());
                        _general_map["sdklog_dir"] = false;
                    }
                    if (_general_map["sdklog_level"]) {
                        it->second["sdklog"]["loglevel"] = sdklog_level;
                        _config_st.sdklog_level = sdklog_level;
                        _general_map["sdklog_level"] = false;
                    }
                    if (_general_map["sdklog_autodel"]) {
                        it->second["sdklog"]["autodel"] = sdklog_autodel;
                        _config_st.sdklog_autodel = sdklog_autodel;
                        _general_map["sdklog_autodel"] = false;
                    }
                    if (_general_map["applog_level"]) {
                        it->second["applog"]["loglevel"] = applog_level;
                        _config_st.applog_level = applog_level;
                        _general_map["applog_level"] = false;
                    }
                    if (_general_map["on_timer_delete_file"]) {
                        it->second["on_timer_delete_file"] = on_timer_delete_file;
                        _config_st.on_timer_delete_file = on_timer_delete_file;
                        _general_map["on_timer_delete_file"] = false;
                    }
                    if (_general_map["file_cache_interval"]) {
                        it->second["file_cache_interval"] = file_cache_interval;
                        _config_st.file_cache_interval = file_cache_interval;
                        _general_map["file_cache_interval"] = false;
                    }
                    config_root["general"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("dev_info") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["dev_info"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("snapshot") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["snapshot"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("mqtt") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["mqtt"] = it->second;
                }
            }
        }
    }

    if (config_root && !config_root.IsNull()) {
        std::ofstream yaml_config_file(config_file);
        yaml_config_file << config_root;
        yaml_config_file.close();
    }

    return true;
}

bool CtrlCfg::update_devinfo_config(std::string serial, std::string ip, uint32_t port, std::string username, std::string password) {
    std::string config_file = get_config_file();
    if (config_file.empty())
        return false;

    YAML::Node root = YAML::LoadFile(_config_file);
    YAML::Node config_root;

    if (root && !root.IsNull()) {
        for (auto it=root.begin(); it!=root.end(); ++it) {
            if (it->first && it->first.as<std::string>().compare("general") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["general"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("dev_info") == 0) {
                if (it->second && !it->second.IsNull()) {
                    if (it->second && !it->second.IsNull()) {
                        for (auto itr = _dvr_cfg_map.begin(); itr != _dvr_cfg_map.end(); ++itr) {
                            if (std::string(itr->second.dev_serial).compare(serial) == 0) {
                                for (auto iter = it->second.begin(); iter != it->second.end(); ++iter) {
                                    if (_devinfo_map["ip"]) {
                                        iter->second["ip"] = ip;
                                        strcpy(itr->second.dev_ip, ip.c_str());
                                        _devinfo_map["ip"] = false;
                                    }
                                    if (_devinfo_map["port"]) {
                                        iter->second["port"] = port;
                                        itr->second.dev_port = port;
                                        _devinfo_map["port"] = false;
                                    }
                                    if (_devinfo_map["username"]) {
                                        iter->second["username"] = username;
                                        stpcpy(itr->second.dev_username, username.c_str());
                                        _devinfo_map["username"] = false;
                                    }
                                    if (_devinfo_map["password"]) {
                                        iter->second["password"] = password;
                                        stpcpy(itr->second.dev_password, password.c_str());
                                        _devinfo_map["password"] = false;
                                    }
                                }
                            }
                            config_root["dev_info"] = it->second;
                        }
                    } 
                }
            }
            if (it->first && it->first.as<std::string>().compare("snapshot") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["snapshot"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("mqtt") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["mqtt"] = it->second;
                }
            }
        }
    }

    if (config_root && !config_root.IsNull()) {
        std::ofstream config_file_stream(config_file);
        config_file_stream << config_root;
        config_file_stream.close();
    }

    return true;
}

bool CtrlCfg::update_snapshot_config(std::string picture_path,
                                     uint32_t picture_quality,
                                     uint32_t picture_size,
                                     std::string upload_mode,
                                     std::string upload_path) {
    std::string config_file = get_config_file();
    if (config_file.empty())
        return false;

    YAML::Node root = YAML::LoadFile(_config_file);
    YAML::Node config_root;

    if (root && !root.IsNull()) {
        for (auto it=root.begin(); it!=root.end(); ++it) {
            if (it->first && it->first.as<std::string>().compare("general") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["general"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("dev_info") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["dev_info"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("snapshot") == 0) {
                if (it->second && !it->second.IsNull()) {
                    if (it->second && !it->second.IsNull()) {
                        if (_snapshot_map["picture_path"]) {
                            it->second["picture_path"] = picture_path;
                            strcpy(_config_st.snapshot_picture_path, picture_path.c_str());
                            _snapshot_map["picture_path"] = false;
                        }
                        if (_snapshot_map["picture_quality"]) {
                            it->second["picture_para"]["quality"] = picture_quality;
                            _config_st.snapshot_picture_quality = picture_quality;
                            _snapshot_map["picture_quality"] = false;
                        }
                        if (_snapshot_map["picture_size"]) {
                            it->second["picture_para"]["size"] = picture_size;
                            _config_st.snapshot_picture_size = picture_size;
                            _snapshot_map["picture_size"] = false;
                        }
                        if (_snapshot_map["upload_mode"]) {
                            it->second["upload_mode"] = upload_mode;
                            strcpy(_config_st.upload_mode, upload_mode.c_str());
                            _snapshot_map["upload_mode"] = false;
                        }
                        if (_snapshot_map["upload_path"]) {
                            it->second["upload_path"] = upload_path;
                            strcpy(_config_st.upload_path, upload_path.c_str());
                            _snapshot_map["upload_path"] = false;
                        }
                        config_root["snapshot"] = it->second;
                    }                            
                }
            }
            if (it->first && it->first.as<std::string>().compare("mqtt") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["mqtt"] = it->second;
                }
            }
        }
    }

    if (config_root && !config_root.IsNull()) {
        std::ofstream config_file_stream(config_file);
        config_file_stream << config_root;
        config_file_stream.close();
    }

    return true;
}

bool CtrlCfg::update_mqtt_config(std::string host, uint32_t port, uint32_t keepalive) {
    std::string config_file = get_config_file();
    if (config_file.empty())
        return false;

    YAML::Node root = YAML::LoadFile(_config_file);
    YAML::Node config_root;

    if (root && !root.IsNull()) {
        for (auto it=root.begin(); it!=root.end(); ++it) {
            if (it->first && it->first.as<std::string>().compare("general") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["general"] = it->second;
                }
            }
            if (it->first && it->first.as<std::string>().compare("dev_info") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["dev_info"] = it->second;
                }
            } 
            if (it->first && it->first.as<std::string>().compare("snapshot") == 0) {
                if (it->second && !it->second.IsNull()) {
                    config_root["snapshot"] = it->second;
                }
            } 
            if (it->first && it->first.as<std::string>().compare("mqtt") == 0) {
                if (it->second && !it->second.IsNull()) {
                    if (_mqtt_map["host"]) {
                        it->second["host"] = host;
                        strcpy(_config_st.mqtt_host, host.c_str());
                        _mqtt_map["host"] = false;
                    }
                    if (_mqtt_map["port"]) {
                        it->second["port"] = port;
                        _config_st.mqtt_port = port;
                        _mqtt_map["port"] = false;
                    }
                    if (_mqtt_map["keepalive"]) {
                        it->second["keepalive"] = keepalive;
                        _config_st.mqtt_keepalive = keepalive;
                        _mqtt_map["keepalive"] = false;
                    }
                    config_root["mqtt"] = it->second;
                }
            }
        }
    }

    if (config_root && !config_root.IsNull()) {
        std::ofstream config_file_stream(config_file);
        config_file_stream << config_root;
        config_file_stream.close();
    }

    return true;
}

void CtrlCfg::parse_config(std::string &config_file) {
    YAML::Node root = YAML::LoadFile(config_file);
    if (root) {
        memset(&_config_st, 0, sizeof(_config_st));

        for (auto it=root.begin(); it!=root.end(); ++it) {
            if (it->first && it->first.as<std::string>().compare("general") == 0) {
                if (it->second["on_timer_delete_file"] && !it->second["on_timer_delete_file"].IsNull()) {
                    _config_st.on_timer_delete_file = it->second["on_timer_delete_file"].as<bool>();
                }
                if (it->second["file_cache_interval"] && !it->second["file_cache_interval"].IsNull()) {
                    _config_st.file_cache_interval = it->second["file_cache_interval"].as<uint32_t>();
                }
                YAML::Node level_node = it->second["sdklog"]["loglevel"];
                if (level_node && !level_node.IsNull()) {
                    _config_st.sdklog_level = level_node.as<uint32_t>();
                }
                YAML::Node dir_node = it->second["sdklog"]["logdir"];
                if (dir_node && !dir_node.IsNull()) {
                    std::string dir = dir_node.as<std::string>();
                    sprintf(_config_st.sdklog_dir, "%s", dir.c_str());
                }
                YAML::Node autodel_node = it->second["sdklog"]["autodel"];
                if (autodel_node && !autodel_node.IsNull()) {
                    _config_st.sdklog_autodel = autodel_node.as<bool>();
                }
                YAML::Node app_node = it->second["applog"]["loglevel"];
                if (app_node && !app_node.IsNull()) {
                    _config_st.applog_level = app_node.as<uint32_t>();
                }
            } else if (it->first && it->first.as<std::string>().compare("dev_info") == 0) {
                Dev_Config_ST _dvr_st;
                std::string dev_key;
                std::string dev_serial;
                std::string dev_ip;
                uint32_t dev_port;
                std::string dev_username;
                std::string dev_password;
                for (auto itr=it->second.begin(); itr!=it->second.end(); ++itr) {
                    if (itr->first && !itr->first.IsNull()) {
                        dev_key = itr->first.as<std::string>();
                    }
                    if (itr->second["serial"] && !itr->second["serial"].IsNull()) {
                        dev_serial =  itr->second["serial"].as<std::string>();
                        sprintf(_dvr_st.dev_serial, "%s", dev_serial.c_str());
                    }
                    if (itr->second["ip"] && !itr->second["ip"].IsNull()) {
                        dev_ip = itr->second["ip"].as<std::string>();
                        sprintf(_dvr_st.dev_ip, "%s", dev_ip.c_str());
                    }
                    if (itr->second["port"] && !itr->second["port"].IsNull()) {
                        dev_port = itr->second["port"].as<uint32_t>();
                        _dvr_st.dev_port = dev_port;
                    }
                    if (itr->second["username"] && !itr->second["username"].IsNull()) {
                        dev_username = itr->second["username"].as<std::string>();
                        sprintf(_dvr_st.dev_username, "%s", dev_username.c_str());
                    }
                    if (itr->second["password"] && !itr->second["password"].IsNull()) {
                        dev_password = itr->second["password"].as<std::string>();
                        sprintf(_dvr_st.dev_password, "%s", dev_password.c_str());
                    }
                    _dvr_cfg_map[dev_key] = _dvr_st;
                }

                Dev_Config_Map dev_cfg_map = _config_st.dev_map;
                std::copy(_dvr_cfg_map.begin(), _dvr_cfg_map.end(),
                          std::inserter(dev_cfg_map, dev_cfg_map.end()));

            } else if (it->first && it->first.as<std::string>().compare("snapshot") == 0) {
                if (it->second["picture_path"] && !it->second["picture_path"].IsNull()) {
                    std::string pic_path = it->second["picture_path"].as<std::string>();
                    sprintf(_config_st.snapshot_picture_path, "%s", pic_path.c_str());
                }
                YAML::Node quality_node = it->second["picture_para"]["quality"];
                if (quality_node && !quality_node.IsNull()) {
                    _config_st.snapshot_picture_quality = quality_node.as<uint32_t>();
                }
                YAML::Node size_node = it->second["picture_para"]["size"];
                if (size_node && !size_node.IsNull()) {
                    _config_st.snapshot_picture_size = size_node.as<uint32_t>();
                }
                if (it->second["upload_mode"] && !it->second["upload_mode"].IsNull()) {
                    std::string mode = it->second["upload_mode"].as<std::string>();
                    sprintf(_config_st.upload_mode, "%s", mode.c_str());
                }
                if (it->second["upload_path"] && !it->second["upload_path"].IsNull()) {
                    std::string path = it->second["upload_path"].as<std::string>();
                    sprintf(_config_st.upload_path, "%s", path.c_str());
                }

            } else if (it->first && it->first.as<std::string>().compare("mqtt") == 0) {
                if (it->second["host"] && !it->second["host"].IsNull()) {
                    std::string host = it->second["host"].as<std::string>();
                    sprintf(_config_st.mqtt_host, "%s", host.c_str());
                }
                if (it->second["port"] && !it->second["port"].IsNull()) {
                    _config_st.mqtt_port = it->second["port"].as<uint32_t>();
                }
                if (it->second["keepalive"] && !it->second["keepalive"].IsNull()) {
                    _config_st.mqtt_keepalive = it->second["keepalive"].as<uint32_t>();
                }
            }
        }
    }
}




